home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / contributed / waste / waste 1.3 / source / wescraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  12.1 KB  |  516 lines

  1. /*
  2.  *    WEScraps.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Routines for Manipulating Style Scraps and Object Soups
  6.  *
  7.  *  Copyright (c) 1993-1998 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal OSErr _WEPrependStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offsetDelta)
  18. {
  19.     // compare the stylistic attributes in info with the first element of the specified
  20.     // style scrap: if they differ, prepend a new element to the style scrap.
  21.     // in any case, advance all character offsets in the style scrap by offsetDelta
  22.  
  23.     TEStyleScrap *pScrap;
  24.     TEStyleScrapElement entry;
  25.     SInt16 i;
  26.     OSErr err;
  27.  
  28.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  29.  
  30.     // compare this style info with that stored in the first entry of our private style scrap
  31.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[0].scrpTEAttrs, &info->runAttrs, sizeof(TERunAttributes)))
  32.     {
  33.         // insert a new style scrap entry at the beginning of the style scrap
  34.         entry.scrpStartChar = 0;
  35.         entry.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  36.  
  37.         if ((err = _WESplice(hStyleScrap, &entry, sizeof(entry), sizeof(SInt16))) != noErr)
  38.         {
  39.             return err;
  40.         }
  41.  
  42.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  43.  
  44.         // increment entry count
  45.         pScrap->scrpNStyles++;
  46.  
  47.     } // if not _WEBlockCmp
  48.  
  49.     // update char offsets within the style scrap
  50.     for ( i = pScrap->scrpNStyles - 1; i > 0; i-- )
  51.     {
  52.         pScrap->scrpStyleTab[i].scrpStartChar += offsetDelta;
  53.     }
  54.  
  55.     return noErr;
  56. }
  57.  
  58. pascal OSErr _WEAppendStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offset)
  59. {
  60.  
  61.     // compare the stylistic attributes in info with the last entry of the specified
  62.     // style scrap: if they differ, append a new entry to the style scrap.
  63.  
  64.     TEStyleScrap *pScrap;
  65.     TEStyleScrapElement entry;
  66.     OSErr err;
  67.  
  68.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  69.     // compare this style info with that stored in the first entry of our private style scrap
  70.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[pScrap->scrpNStyles - 1].scrpTEAttrs,
  71.         &info->runAttrs, sizeof(TERunAttributes)))
  72.     {
  73.  
  74.         // create a new style scrap entry
  75.         entry.scrpStartChar = offset;
  76.         entry.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  77.  
  78.         // append it at the end of the style scrap
  79.         if ((err = _WESplice(hStyleScrap, &entry, sizeof(entry), -1)) != noErr)
  80.         {
  81.             return err;
  82.         }
  83.  
  84.         // increment scrap counter
  85.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  86.         pScrap->scrpNStyles++;
  87.  
  88.     } // if not _WEBlockCmp
  89.  
  90.     // return result code
  91.     return noErr;
  92. }
  93.  
  94. #if WASTE_OBJECTS
  95.  
  96. pascal OSErr _WEPrependObject(Handle hSoup, const WERunInfo *info, SInt32 offsetDelta)
  97. {
  98.     // if info describes an embedded object, prepend a new object descriptor,
  99.     // complete with the associated object data, to the specified soup.
  100.     // in any case, advance all character offsets in the soup by offsetDelta
  101.  
  102.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  103.     Handle hObjectData = nil;
  104.     FlavorType objectType;
  105.     Boolean disposeData;
  106.     Ptr pSoup;
  107.     WESoup soup;
  108.     Size soupSize, objectDataSize, extraSize;
  109.     OSErr err;
  110.  
  111.     // get size of existing soup
  112.     soupSize = GetHandleSize(hSoup);
  113.  
  114.     if (hObjectDesc != nil)
  115.     {
  116.         // create a temporary handle for the streaming callback
  117.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  118.         {
  119.             goto cleanup;
  120.         }
  121.  
  122.         // get the object type/data
  123.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  124.         {
  125.             goto cleanup;
  126.         }
  127.  
  128.         // get size of object data
  129.         objectDataSize = GetHandleSize(hObjectData);
  130.  
  131.         // extraSize is size of descriptor + size of object data
  132.         extraSize = sizeof(soup) + objectDataSize;
  133.  
  134.         // fill in a soup item
  135.         BLOCK_CLR(soup);
  136.         soup.soupType = objectType;
  137.         soup.soupSize = (*hObjectDesc)->objectSize;
  138.         soup.soupDataSize = objectDataSize;
  139.  
  140.         // make room for the descriptor and the object data
  141.         if ((err = _WESplice(hSoup, nil, extraSize, 0)) != noErr)
  142.         {
  143.             goto cleanup;
  144.         }
  145.  
  146.         // insert the new object descriptor at the beginning
  147.         pSoup = *hSoup;
  148.         BlockMoveData(&soup, pSoup, sizeof(soup));
  149.  
  150.         // copy the object data
  151.         BlockMoveData(*hObjectData, pSoup + sizeof(soup), objectDataSize);
  152.     }
  153.     else
  154.     {
  155.         pSoup = *hSoup;
  156.         extraSize = 0;
  157.     }
  158.  
  159.     // update char offsets within the soup
  160.     while (soupSize > 0)
  161.     {
  162.         pSoup += extraSize;
  163.  
  164.         //    we have to use BlockMoveData to access descriptors within
  165.         //    the soup, as they might be odd-aligned (duh!) and that would
  166.         //    cause fatal address errors on 68000 CPUs
  167.  
  168.         BlockMoveData(pSoup, &soup, sizeof(soup));
  169.         soup.soupOffset += offsetDelta;
  170.         BlockMoveData(&soup, pSoup, sizeof(soup));
  171.         extraSize = sizeof(soup) + soup.soupDataSize;
  172.         soupSize -= extraSize;
  173.     }
  174.  
  175.     err = noErr;
  176.  
  177. cleanup:
  178.     if (disposeData)
  179.     {
  180.         _WEForgetHandle(&hObjectData);
  181.     }
  182.  
  183.     return err;
  184.  
  185. }
  186.  
  187. pascal OSErr _WEAppendObject(Handle hSoup, const WERunInfo *info, SInt32 offset)
  188. {
  189.  
  190.     // if info describes an embedded object, append a new object descriptor,
  191.     // complete with the associated object data, to the specified soup.
  192.  
  193.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  194.     Handle hObjectData = nil;
  195.     FlavorType objectType;
  196.     WESoup soup;
  197.     Boolean saveDataLock;
  198.     Boolean disposeData;
  199.     OSErr err;
  200.  
  201.     if (hObjectDesc != nil)
  202.     {
  203.         // create a temporary handle for the streaming callback
  204.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  205.         {
  206.             goto cleanup;
  207.         }
  208.  
  209.         // get the object type/data
  210.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  211.         {
  212.             goto cleanup;
  213.         }
  214.  
  215.         // fill in a soup item
  216.         BLOCK_CLR(soup);
  217.         soup.soupOffset = offset;
  218.         soup.soupType = objectType;
  219.         soup.soupSize = (*hObjectDesc)->objectSize;
  220.         soup.soupDataSize = GetHandleSize(hObjectData);
  221.  
  222.         // append it to the soup handle
  223.         if ((err = _WESplice(hSoup, &soup, sizeof(soup), -1)) != noErr)
  224.         {
  225.             goto cleanup;
  226.         }
  227.  
  228.         // append the actual object data to the soup handle
  229.         saveDataLock = _WESetHandleLock(hObjectData, true);
  230.         err = _WESplice(hSoup, *hObjectData, soup.soupDataSize, -1);
  231.         _WESetHandleLock(hObjectData, saveDataLock);
  232.         if (err != noErr)
  233.         {
  234.             goto cleanup;
  235.         }
  236.     } // if object reference is not nil
  237.  
  238.     err = noErr;
  239.  
  240. cleanup:
  241.     if (disposeData)
  242.     {
  243.         _WEForgetHandle(&hObjectData);
  244.     }
  245.  
  246.     return err;
  247.  
  248. }
  249.  
  250. #endif
  251.  
  252. pascal OSErr WECopyRange(SInt32 rangeStart, SInt32 rangeEnd, Handle hText,
  253.                     Handle hStyles, Handle hSoup, WEHandle hWE)
  254. {
  255.  
  256.     // Make a copy of the specified range of text: store the characters in hText
  257.     // and the associated style scrap in hStyles.  The handles are resized as necessary.
  258.     // Specify nil in hText or hStyles if you don't want the corresponding info returned.
  259.  
  260.     WEPtr pWE;
  261.     TEStyleScrapElement *pEntry = nil;
  262.     SInt32 rangeLength;
  263.     SInt32 firstRun, nRuns, i;
  264.     SInt32 startChar;
  265.     WERunInfo info;
  266.     Boolean saveWELock;
  267.     OSErr err;
  268.  
  269.     // lock the WE record
  270.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  271.     pWE = *hWE;
  272.  
  273.     // range-check parameters and reorder them if necessary
  274.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  275.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  276.     _WEReorder(&rangeStart, &rangeEnd);
  277.     rangeLength = rangeEnd - rangeStart;
  278.  
  279.     if (hText != nil)
  280.     {
  281.         // resize the given handle
  282.         SetHandleSize(hText, rangeLength);
  283.         if ((err = MemError()) != noErr)
  284.         {
  285.             goto cleanup;
  286.         }
  287.  
  288.         // copy the text range
  289.         BlockMoveData(*pWE->hText + rangeStart, *hText, rangeLength);
  290.     }
  291.  
  292.     // make the soup handle zero-length
  293.     if (hSoup != nil)
  294.     {
  295.         SetHandleSize(hSoup, 0);
  296.         if ((err = MemError()) != noErr)
  297.         {
  298.             goto cleanup;
  299.         }
  300.     }
  301.  
  302.     if ((hStyles != nil) || (hSoup != nil))
  303.     {
  304.         // count how many style runs there are in the selection range
  305.         firstRun = WEOffsetToRun(rangeStart, hWE);
  306.         nRuns = WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  307.  
  308.         if (hStyles != nil)
  309.         {
  310.             // resize the given style scrap handle and lock it in high heap
  311.             SetHandleSize(hStyles, (nRuns * sizeof(ScrpSTElement)) + sizeof(SInt16));
  312.             if ((err = MemError()) != noErr)
  313.             {
  314.                 goto cleanup;
  315.             }
  316.             HLockHi(hStyles);
  317.  
  318.             // fill in the entry count in the style scrap
  319.             // pin the entry count at 32,767
  320.             (* (TEStyleScrapHandle) hStyles)->scrpNStyles = (nRuns < SHRT_MAX) ? nRuns : SHRT_MAX;
  321.  
  322.             // get pointer to first style table element
  323.             pEntry = & ((* (TEStyleScrapHandle) hStyles)->scrpStyleTab[0]);
  324.         }
  325.  
  326.         // loop through every style run in the selection range
  327.         for ( i = 0; i < nRuns; i++ )
  328.         {
  329.             _WEGetIndStyle(firstRun + i, &info, hWE);
  330.  
  331.             // calculate the start character for this style run, relative to the beginning of the range
  332.             startChar = info.runStart - rangeStart;
  333.             if (startChar < 0)
  334.             {
  335.                 startChar = 0;
  336. #if WASTE_OBJECTS
  337.                 info.runAttrs.runStyle.tsObject = nil;
  338. #endif
  339.             }
  340.             if (hStyles != nil)
  341.             {
  342.                 info.runAttrs.runStyle.tsFlags = 0; // don't export internal flags
  343.                 pEntry->scrpStartChar = startChar;
  344.                 pEntry->scrpTEAttrs = * (TERunAttributes *) &info.runAttrs;
  345.                 pEntry++;
  346.             }
  347.  
  348. #if WASTE_OBJECTS
  349.             if (hSoup != nil)
  350.             {
  351.                 // if this style run references an embedded object, append it to the "soup"
  352.                 if (info.runAttrs.runStyle.tsObject != nil)
  353.                 {
  354.                     if ((err = _WEAppendObject(hSoup, &info, startChar)) != noErr)
  355.                     {
  356.                         goto cleanup;
  357.                     }
  358.                 }
  359.             }
  360. #endif
  361.  
  362.         }
  363.     }
  364.     // clear result code
  365.     err = noErr;
  366.  
  367. cleanup:
  368.  
  369.     // unlock the style scrap handle
  370.     if (hStyles != nil)
  371.     {
  372.         HUnlock(hStyles);
  373.     }
  374.  
  375.     // unlock the WE record
  376.     _WESetHandleLock((Handle) hWE, saveWELock);
  377.     // return result code
  378.     return err;
  379. }
  380.  
  381. pascal OSErr _WEPutScrapHandle ( FlavorType dataFlavor, Handle dataHandle )
  382. {
  383.     Boolean saveDataLock ;
  384.     OSErr err ;
  385.  
  386.     saveDataLock = _WESetHandleLock ( dataHandle, true ) ;
  387.     err = PutScrap ( GetHandleSize ( dataHandle ), dataFlavor, * dataHandle ) ;
  388.     _WESetHandleLock ( dataHandle, saveDataLock ) ;
  389.  
  390.     return err ;
  391. }
  392.  
  393. pascal OSErr WECopy ( WEHandle hWE )
  394. {
  395.     //    copy the selection range to the desk scrap
  396.  
  397.     WEPtr pWE ;
  398.     Handle dataHandle = nil ;
  399.     Boolean saveWELock;
  400.     OSErr err;
  401. #if WASTE_OBJECTS
  402.     WEObjectDescHandle hObjectDesc = nil;
  403. #endif
  404.  
  405.     //    lock the WE record
  406.     saveWELock = _WESetHandleLock ( ( Handle ) hWE, true ) ;
  407.     pWE = * hWE ;
  408.  
  409.     //    return weEmptySelectionErr if the selection range is empty
  410.     err = weEmptySelectionErr ;
  411.     if ( pWE -> selStart == pWE -> selEnd )
  412.     {
  413.         goto cleanup ;
  414.     }
  415.  
  416.     //    clear the desk scrap
  417.     if ( ( err = ZeroScrap ( ) ) != noErr )
  418.     {
  419.         goto cleanup ;
  420.     }
  421.  
  422.     //    allocate a temporary handle
  423.     if ( ( err = _WEAllocate ( 0, kAllocTemp, & dataHandle ) ) != noErr )
  424.     {
  425.         goto cleanup ;
  426.     }
  427.  
  428. #if WASTE_OBJECTS
  429.     //    is there a selected object?
  430.     if ( WEGetSelectedObject ( & hObjectDesc, hWE ) == noErr )
  431.     {
  432.         FlavorType objectType = 0 ;
  433.         Boolean disposeData = false ;
  434.  
  435.         //    stream it
  436.         if ( ( err = _WEStreamObject ( weToScrap, & objectType, & dataHandle,
  437.                 & disposeData, hObjectDesc ) ) != noErr )
  438.         {
  439.             goto cleanup ;
  440.         }
  441.  
  442.         //    put it on the scrap
  443.         if ( ( err = _WEPutScrapHandle ( objectType, dataHandle ) ) != noErr )
  444.         {
  445.             goto cleanup ;
  446.         }
  447.  
  448.         if ( ! disposeData )
  449.         {
  450.             dataHandle = nil ;
  451.         }
  452.     }
  453.     else
  454. #endif
  455.     {
  456.         //    make a copy of the selected text
  457.         if ( ( err = WECopyRange ( pWE -> selStart, pWE -> selEnd, dataHandle, nil, nil, hWE ) ) != noErr )
  458.         {
  459.             goto cleanup ;
  460.         }
  461.  
  462.         //    put it on the scrap
  463.         if ( ( err = _WEPutScrapHandle ( kTypeText, dataHandle ) ) != noErr )
  464.         {
  465.             goto cleanup ;
  466.         }
  467.  
  468.         //    don't copy styles/soup if the text is monostyled
  469.         if ( ! BTST ( pWE -> features, weFMonoStyled ) )
  470.         {
  471.             //    build & copy a style scrap
  472.             if ( ( err = WECopyRange ( pWE -> selStart, pWE -> selEnd, nil, dataHandle, nil, hWE ) ) != noErr )
  473.             {
  474.                 goto cleanup ;
  475.             }
  476.             if ( ( err = _WEPutScrapHandle ( kTypeStyles, dataHandle ) ) != noErr )
  477.             {
  478.                 goto cleanup ;
  479.             }
  480.  
  481.             //    build & copy a font table
  482.             if ( ( err = WEBuildFontTable ( dataHandle, nil, hWE ) ) != noErr )
  483.             {
  484.                 goto cleanup ;
  485.             }
  486.             if ( ( err = _WEPutScrapHandle ( kTypeFontTable, dataHandle ) ) != noErr )
  487.             {
  488.                 goto cleanup ;
  489.             }
  490.  
  491. #if WASTE_OBJECTS
  492.             //    build & copy an object soup
  493.             if ( ( err = WECopyRange ( pWE -> selStart, pWE -> selEnd, nil, nil, dataHandle, hWE ) ) != noErr )
  494.             {
  495.                 goto cleanup ;
  496.             }
  497.             if ( ( err = _WEPutScrapHandle ( kTypeSoup, dataHandle ) ) != noErr )
  498.             {
  499.                 goto cleanup ;
  500.             }
  501. #endif
  502.         }
  503.     }
  504.  
  505.     //    clear result code
  506.     err = noErr;
  507.  
  508. cleanup:
  509.     //    clean up
  510.     _WEForgetHandle ( & dataHandle ) ;
  511.     _WESetHandleLock ( ( Handle ) hWE, saveWELock ) ;
  512.  
  513.     //    return result code
  514.     return err ;
  515. }
  516.